// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License 2.0 for more details.

// Copyright (C) 2012-2013	JoostinOnline

/*--------------------------------------------------------------------

 CheckRegion by JoostinOnline

 While AnyRegionChanger (and its mods) can modify all the region
 settings that are needed for the Wii to work, it does not change
 the value of "CODE", which are the letters that precede the serial
 number.  From that, you can determine the original region.


						***IMPORTANT***
 If your Wii was purchased before May 2011 or does not have GC ports,
 the report should be 100% accurate.

 If that's not the case, there is a chance someone used GiantPune's
 Ohneschwanzenegger and a GC controller to create a new NAND, which
 allows a custom serial number, thus fooling CheckRegion.  You can
 only then assume it's right if it reports a different region than
 your Wii's current one.

--------------------------------------------------------------------*/

#include <CheckRegion.h>
#include <ogc/pad.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <wiiuse/wpad.h>
#include <runtimeiospatch/runtimeiospatch.h>

// Colors for debug output
#define	RED		"\x1b[31;1m"
#define	GREEN	"\x1b[32;1m"
#define	YELLOW	"\x1b[33;1m"
#define	WHITE	"\x1b[37;1m"

// Remeber to set it back to WHITE when you're done
#define CHANGE_COLOR(X)	(printf((X)))

// C is stupid and can't print a signed int in hex form with printf, so I made a macro
// Arguments are a string (such as "ret = "), then the error value
#define PRINT_HEX_ERROR(S,E) (printf("%s%c0x%X\n",(S),((E)<0)?'-':' ',((E)<0)?-(E):(E)))

extern void __exception_setreload(int t);
void Video_Initialize(void);

int main(int argc, char *argv[]) {
	// Exit after 2 seconds if there is an error
	__exception_setreload(2);
	s32 ret;
	Video_Initialize();
	WPAD_Init();
	PAD_Init();

	printf("\x1b[2;0H");
	printf("CheckRegion v%s by JoostinOnline - HacksDen.com\n\n\n", CHECKREGION_VERSION);
	if (CONF_Init())
	{
		CHANGE_COLOR(RED);
		printf("Error opening setting.txt, exiting...");
		sleep(3);
		exit(0);
	}

	CHANGE_COLOR(GREEN);

	// model is only reported if the serial code is not recognized.  This will
	// help match the code with its region.
	char model[MODEL_SIZE] = {0};


	// The Shop Code tells you what country your Wii is set to.  This is set when
	// you first load the Shop Channel.  Changing it will block access to the
	// channel unless you delete your account first.
	u8 shopcode = 0;
	if (CONF_GetShopCode(&shopcode) >= 0) {
		printf("Shop code: %u (%s)\n", shopcode, (strlen(CONF_CountryCodes[shopcode]) ? CONF_CountryCodes[shopcode] : "Unknown Country"));
	} else {
		CHANGE_COLOR(RED);
		printf("Error getting shop code!\n");
		CHANGE_COLOR(GREEN);
	}

	// serialcode (or whatever you name the variable) is important because
	// you can still learn what CODE is set to, should it not be identified
	// already. If you don't want the code as a string for whatever reason,
	// then use CONF_GetSerialCode(NULL)
	char serialcode[SERIALCODE_SIZE] = "???\0";

	// ret will either be equal to one of the CONF_CODE_* or the CONF_E*
	// variables in CheckRegion.h
	ret = CONF_GetSerialCode(serialcode);
	printf("You have a");

	switch (ret) {
		case CONF_CODE_JPN:
			// LJF - Confirmed
			printf(" Japanese Wii");
			break;
		case CONF_CODE_USA:
			// LU - Confirmed
			printf(" USA Wii");
			break;
		case CONF_CODE_EURH:
			// LEH - Confirmed
		case CONF_CODE_EURM:
			// LEM - Confirmed
		case CONF_CODE_EURF:
			// LEF - Confirmed
			printf(" European Wii");
			break;
		case CONF_CODE_KOR:
			// LKM - Confirmed
			printf(" Korean Wii");
			break;
		case CONF_CODE_AUS:
			// LAH - Confirmed
			printf("n Australian Wii");
			break;
		case CONF_CODE_USAK:
			// KU - Confirmed (thanks LiNkZoR)
			printf(" new USA Wii");
			break;
		case CONF_CODE_EURHK:
			// KEH - Confirmed (thanks JohnyNyga)
		case CONF_CODE_EURMK:
			// KEM - Confirmed (thanks VampireLordAlucard)
		case CONF_CODE_EURFK:
			// KEF - Confirmed (thanks sureiya)
			printf(" new European Wii");
			break;
		case CONF_CODE_AUSK:
			// KAM - Confirmed (thanks Drexyl)
			printf(" new Australian Wii");
			break;
		case CONF_CODE_DLPH:
			// LE - Confirmed by myself
			printf("\rYou are running Dolphin");
			break;
		case CONF_CODE_VJPNI:
			printf("n 8GB Japanese Wii U");
			break;
		case CONF_CODE_VJPNO:
			printf(" 32GB Wii U");
			break;
		case CONF_CODE_VUSAI:
			printf(" 8GB USA Wii U");
			break;
		case CONF_CODE_VUSAO:
			printf(" 32GB USA Wii U");
			break;
		case CONF_CODE_VEURHI:
		case CONF_CODE_VEURMI:
		case CONF_CODE_VEURFI:
			printf("n 8GB European Wii U");
			break;
		case CONF_CODE_VEURHO:
		case CONF_CODE_VEURMO:
		case CONF_CODE_VEURFO:
			printf(" 32GB European Wii U");
			break;
		case CONF_CODE_VKORI:
			printf("n 8GB Korean Wii U");
			break;
		case CONF_CODE_VKORO:
			printf(" 32GB Korean Wii U");
			break;
		case CONF_CODE_VAUSI:
			printf("n 8GB Australian Wii U");
			break;
		case CONF_CODE_VAUSO:
			printf(" 32GB Australian Wii U");
			break;
		case CONF_EBADVALUE:
			// Able to get the code, but not defined in CheckRegion.h

			CHANGE_COLOR(YELLOW);

			printf("\rYour serial code is unregistered!\n");
			printf("\nYour serial number starts with %s", serialcode);

			// something to match the code with that can't be modified with ARC
			if (!CONF_GetModel(model)) printf("\nYour Wii's model number is %s", model);

			printf("\n\nPlease report your model and code at tinyurl.com/CheckRegion");
			printf("\nYour assistance would be most helpful");
			break;
		default:
			// __CONF_GetTxt returned an error
			CHANGE_COLOR(RED);
			printf("\rError getting region code!\n");
			PRINT_HEX_ERROR("ret = ", ret);
			break;
	}


	// The serial number isn't really important, as it doesn't tell you anything
	// special.  So why did I add it?  BECAUSE I CAN!!!
	// You can use NULL instead of serialnumber if you want
	char serialnumber[SERIALNUMBER_SIZE] = "?????????\0";
	ret = CONF_GetSerialNumber(serialnumber);
	if (!ret) {
		CHANGE_COLOR(GREEN);	
		printf("\nSerial number: %s%s\n", serialcode, serialnumber);
	} else {
		CHANGE_COLOR(RED);
		printf("\nError getting serial number!\n");
		PRINT_HEX_ERROR("ret = ", ret);
	}

	CHANGE_COLOR(WHITE);
	
	printf("\n\nPress any button to exit");
	while(1) {
		WPAD_ScanPads();
		PAD_ScanPads();
		if ((WPAD_ButtonsDown(0)) || (PAD_ButtonsDown(0))) {
			printf("\nExiting...");
			exit(0);
		}
		VIDEO_WaitVSync();
	}
	return 0;
}